﻿/**
 *
 * master.c
 * @brief 各种协议的主机端请求后的接收回复处理
 *
 *  Created on: 2019-05-05
 *      Author: chenshisheng
 */

#include "master.h"
#include "serial.h"
#include "ctimer.h"
#include "utils.h"

#define AT_CLIENT_RX_BUF_SIZE 64

static struct _Timer
{
    Ctimer_t frame;
    Ctimer_t respond;
}_timer;

static struct _RxCtrl
{
    Serial_t serial;
    uint8_t head;
    int respondTimeout;
    int frameTimeout;
    unsigned int sizeRequired;
    Master_State_t state;
    unsigned int rxSize;
    unsigned int offset;
    uint8_t rxBuf[AT_CLIENT_RX_BUF_SIZE];
    Master_FrameCheck_t check;
} _masterRxCtrl;

void Master_Init(void)
{
    _masterRxCtrl.state = Master_State_Idle;
}

static void _OnFrameEnded(int data)
{

    if(_masterRxCtrl.check(_masterRxCtrl.rxBuf, _masterRxCtrl.rxSize))
    {
        _masterRxCtrl.state = Master_State_FrameIn;
        Master_StopRx();
    }
    else
    {
        _masterRxCtrl.rxSize = 0;  // 重新开始接收
    }
}

static void _OnRespondTimeout(int data)
{

    if(_masterRxCtrl.check(_masterRxCtrl.rxBuf, _masterRxCtrl.rxSize))
    {
        _masterRxCtrl.state = Master_State_FrameIn;
    }
    else
    {
        _masterRxCtrl.state = Master_State_Timeout;
    }
}

static bool _RxByte(Serial_t serial, uint8_t b)
{
    if(_masterRxCtrl.state != Master_State_Rxing)
    {
        return false;
    }

    if((_masterRxCtrl.rxSize == 0) && (b != _masterRxCtrl.head))
    {
        return false;
    }

    if(!Ctimer_IsRunning(&_timer.frame))
    {
        Ctimer_Start(
                &_timer.frame,
                _masterRxCtrl.frameTimeout,
                _OnFrameEnded,
                CTIMER_FLAG_URGEN | CTIMER_FLAG_ONCE,
                0);
    }
    else
    {
        Ctimer_Reset(&_timer.frame);
    }

    if((_masterRxCtrl.rxSize >= _masterRxCtrl.sizeRequired) ||
            (_masterRxCtrl.rxSize >= AT_CLIENT_RX_BUF_SIZE))
    {
        return false;
    }

    _masterRxCtrl.rxBuf[_masterRxCtrl.rxSize] = b;
    _masterRxCtrl.rxSize ++;
    if(_masterRxCtrl.rxSize >= _masterRxCtrl.sizeRequired)
    {
        if(_masterRxCtrl.check(_masterRxCtrl.rxBuf, _masterRxCtrl.rxSize))
        {
            _masterRxCtrl.state = Master_State_FrameIn;
            Master_StopRx();
        }
    }

    return false;
}

/**
 * 按3.5个字符间隔，根据串口波特率计算帧间隔时长
 * @param serial
 * @return 帧间隔时长（ms）
 */
static unsigned int _CalcFrameGap(Serial_t serial)
{
    uint32_t baud;
    unsigned int gap;

    baud = Serial_GetBaudRate(serial);
    gap =  (unsigned int)(4 * 10 * 1000) / baud;
    if(gap == 0)
    {
        gap = 1;
    }

    return gap;
}

void Master_StartRx(const Master_Rx_t *rx)
{
    int t;

    assert_param(rx->size <= AT_CLIENT_RX_BUF_SIZE);

    t = _CalcFrameGap(rx->serial);
    if(t < (2 *UTILS_SYSTICK_INTERVAL))
    {
        t = 2 * UTILS_SYSTICK_INTERVAL;
    }

    _masterRxCtrl.serial = rx->serial;
    _masterRxCtrl.head = rx->head;
    _masterRxCtrl.rxSize = 0;
    _masterRxCtrl.offset = 0;
    _masterRxCtrl.sizeRequired = rx->size;
    _masterRxCtrl.respondTimeout = rx->timeout;
    _masterRxCtrl.frameTimeout = t;
    _masterRxCtrl.check = rx->check;
    _masterRxCtrl.state = Master_State_Rxing;

    Serial_SetCallbacks(_masterRxCtrl.serial, NULL, NULL, _RxByte);
    Ctimer_Start(
            &_timer.respond,
            _masterRxCtrl.respondTimeout,
            _OnRespondTimeout,
            CTIMER_FLAG_URGEN | CTIMER_FLAG_ONCE,
            0);

    Serial_IoCtl(_masterRxCtrl.serial, Serial_Ctl_RxCmd, ENABLE);
}

static bool _DummyRxByte(Serial_t serial, uint8_t b)
{
    UNUSED(serial);
    UNUSED(b);

    return false;
}

void Master_StopRx(void)
{
    Serial_IoCtl(_masterRxCtrl.serial, Serial_Ctl_RxCmd, DISABLE);
    Serial_SetCallbacks(_masterRxCtrl.serial, NULL, NULL, _DummyRxByte);
    Ctimer_Stop(&_timer.respond);
    Ctimer_Stop(&_timer.frame);
    if(_masterRxCtrl.state == Master_State_Rxing)
    {
        _masterRxCtrl.state = Master_State_Idle;
    }
}

Master_State_t Master_State(void)
{
    return _masterRxCtrl.state;
}

int Master_RxBufferRead(unsigned int offset, void *dataOut, unsigned int size)
{
    int ret;

    if((size + offset) <= _masterRxCtrl.rxSize)
    {
        memcpy(dataOut, &_masterRxCtrl.rxBuf[offset], size);
        ret = 0;
    }
    else
    {
        ret = -1;
    }

    return ret;
}

void Master_SetRxBufferOffset(unsigned int offset)
{
    _masterRxCtrl.offset = offset;
}

int Master_RxBufferTake(void *dataOut, unsigned int size)
{
    int ret;

    ret = Master_RxBufferRead(_masterRxCtrl.offset, dataOut, size);
    if(ret == 0)
    {
        _masterRxCtrl.offset += size;
    }

    return ret;
}

unsigned int Master_RxSize(void)
{
    return _masterRxCtrl.rxSize;
}
